//all in game entities derive from this


var doll = (function(_doll) {
"use strict";

_doll.entity = _doll.entity || {};

_doll.entity.id = 0;

//an entity has management related information
_doll.entity.make_entity = function(o, options) {
    o = o || {};
    options = options || {};
    o.is_entity = true;

    //options
    o.type = 'Basic';
    o.events = [];
    o.delayed_events = []
    
    o.set_options = function(opts) {
        for (o in opts) {
            var val = opts[o];
            if(val === undefined) {
                console.warn('doll.entity: undefined value ' + val + ' passed as option.');
                continue;
            }
            
            if(o in t) {
                var curVal = t[o];
                if(curVal instanceof THREE.Color) {
                    curVal.set(val);
                } else if(curVal instanceof THREE.Vector3 && val instanceof THREE.Vector3) {
                    curVal.copy(val);
                } else {
                    t[o] = val;
                }
            }
        }
    }

    o.set_options(options);

    o.id = _doll.entity.id++;
    o.toString = function () { return '<' + o.type + ' ' + o.id + '>'; }

    return o;
}

//updates an entity typically called once per frame
//ex: for_each(objects, doll.entity.update, [delta])

//add an event to process to an entity an event is just a function
//events modify the state of an entity and/or all of its components
//before each component is processed by its particular subsystem
//TODO: could change to add_physics_event, add_game_event, etc
//then process_physics_events, process_game_events, etc maybe?
//doll.entity.add_event.call(entity, event, event_data, delay);
//for_each(entities, doll.entity.add_event, event, event_data, delay);
_doll.entity.add_event = function(evt, data, delay) {
    evt.data = data || {};
    if(delay) {
        evt.data.delay = delay;
        this.delayed_events[this.delayed_events.length] = evt;
    } else {
        this.events[this.events.length] = evt;
    }
};

//typically called once per frame
//updates with special updates based on type value of entity
_doll.entity.update = function(dt) {
    if(!this.is_entity) {
        console.warn('entity.update: tried to update a non-entity!');
        return;
    }

    //update an object based on game object type. game specific.
    //'Enemy', 'Dangerous', 'StaticGeom'
    for (type in _doll.entity.update.type) {
        if(this.type == type) {
            _doll.entity.update.type[type].apply(this);
        }
    }    

    _doll.entity.process_events.call(this, dt);
};
//alternate name
_doll.entity.start_frame = _doll.entity.update;
//set an update function a specific type of entity
_doll.entity.update.type = [];

//process all events this entity was sent
//TODO: could base it on subsystem process_physics_events,
//process_game_events, etc?
_doll.entity.process_events = function (dt) {
    if(!this.is_entity) {
        console.warn('entity.process_events: tried to process the events of a non-entity!');
        return;
    }

    if(e.data == undefined) {
        console.error('entity.process_events: event data is undefined!');
    }

    for(var i=0; i<this.delayed_events.length; i++) {
        var e = this.delayed_events[i];
        e.data.delay--;

        if(e.data.delay < 0) {
            _doll.entity.add_event.call(this, e, e.data);
        }
    }

    for(var i=0; i<this.events.length; i++) {
        var evt = this.events[i];
        evt.data.dt = dt;
        evt.call(this, evt.data);
    }

    this.events.length = 0;
};


return _doll;
}(doll || {}));

